package com.travelgroup.utils;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.travelgroup.constant.RedisConstant;
import com.travelgroup.exception.BusinessException;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

@Component
public class RedisUtil {
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 设置缓存
     * @param key
     * @param value
     */
    public void set(String key, String value) {
        stringRedisTemplate.opsForValue().set(key, value);
    }

    /**
     * 根据键值获取Redis中缓存
     * @param key
     * @param id
     * @param type
     * @param function
     * @param time
     * @param unit
     * @return
     * @param <R>
     * @param <ID>
     */
    public <R, ID> R queryById(String key, ID id, Class<R> type, Function<ID, R> function, Long time, TimeUnit unit) {
        key = key + id;
        String value = stringRedisTemplate.opsForValue().get(key);

        // 判断数据是否缓存
        if (StrUtil.isNotBlank(value)) {
            return JSONUtil.toBean(value, type);
        }
        // 判断是否为空值
        if (value != null) {
            throw new BusinessException("缓存为空");
        }

        // 缓存不存在从数据库中获取
        R result = function.apply(id);

        checkValue(key, result, time, unit);
        return result;
    }

    /**
     * 删除缓存
     * @param key
     * @param id
     * @param <ID>
     */
    public <ID> void removeById(String key, ID id) {
        stringRedisTemplate.delete(key + id);
    }

    /**
     * 查询批量缓存
     * @param key
     * @param id
     * @param type
     * @param function
     * @param time
     * @param unit
     * @return
     * @param <R>
     * @param <ID>
     */
    public <R, ID> List<R> queryListById(String key, ID id, Class<R> type, Function<ID, List<R>> function, Long time, TimeUnit unit) {
        key = key + id;
        String value = stringRedisTemplate.opsForValue().get(key);

        // 判断数据是否缓存
        if (StrUtil.isNotBlank(value)) {
            return JSONUtil.toList(value, type);
        }
        // 判断是否为空值
        if (value != null) {
            throw new BusinessException("缓存为空");
        }

        // 缓存不存在从数据库中获取
        List<R> result = function.apply(id);
        checkValue(key, result, time, unit);
        return result;
    }

    /**
     * 检查数据是否存在
     * @param key
     * @param result
     * @param time
     * @param unit
     */
    private void checkValue(String key, Object result, Long time, TimeUnit unit) {
        if (result == null) {
            stringRedisTemplate.opsForValue().set(key, "", RedisConstant.CACHE_TTL, TimeUnit.MINUTES);
            throw new BusinessException("数据不存在");
        }

        // 设置随机时间防止雪崩
        stringRedisTemplate.opsForValue().set(key, JSONUtil.toJsonStr(result), time + RandomUtil.randomLong(1, 10), unit);
    }
}
